#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
标准化日志输出模块
遵循Linux syslog规范（RFC 5424），支持SIEM系统对接
"""

import os
import sys
import json
import time
import socket
import logging
import logging.handlers
from datetime import datetime
from enum import Enum
from typing import Dict, Any, Optional, List
import threading


class LogLevel(Enum):
    """日志级别枚举"""
    EMERGENCY = 0   # 系统不可用
    ALERT = 1       # 必须立即采取行动
    CRITICAL = 2    # 严重错误
    ERROR = 3       # 错误
    WARNING = 4     # 警告
    NOTICE = 5      # 正常但重要的事件
    INFO = 6        # 信息性消息
    DEBUG = 7       # 调试信息


class LogFacility(Enum):
    """日志设施枚举"""
    KERNEL = 0          # 内核消息
    USER = 1            # 用户级消息
    MAIL = 2            # 邮件系统
    DAEMON = 3          # 系统守护进程
    AUTH = 4            # 安全/授权消息
    SYSLOG = 5          # syslogd内部消息
    LPR = 6             # 行式打印机子系统
    NEWS = 7            # 网络新闻子系统
    UUCP = 8            # UUCP子系统
    CRON = 9            # 时钟守护进程
    AUTHPRIV = 10       # 安全/授权消息（私有）
    FTP = 11            # FTP守护进程
    LOCAL0 = 16         # 本地使用设施0
    LOCAL1 = 17         # 本地使用设施1
    LOCAL2 = 18         # 本地使用设施2
    LOCAL3 = 19         # 本地使用设施3
    LOCAL4 = 20         # 本地使用设施4
    LOCAL5 = 21         # 本地使用设施5
    LOCAL6 = 22         # 本地使用设施6
    LOCAL7 = 23         # 本地使用设施7


class SIEMFormat(Enum):
    """SIEM格式枚举"""
    CEF = "cef"         # Common Event Format
    LEEF = "leef"       # Log Event Extended Format
    JSON = "json"       # JSON格式
    SYSLOG = "syslog"   # 标准syslog格式


class StandardLogger:
    """标准化日志记录器"""
    
    def __init__(self, 
                 app_name: str = "privilege_ma",
                 facility: LogFacility = LogFacility.LOCAL0,
                 hostname: Optional[str] = None,
                 process_id: Optional[int] = None):
        """
        初始化标准化日志记录器
        
        Args:
            app_name: 应用程序名称
            facility: 日志设施
            hostname: 主机名
            process_id: 进程ID
        """
        self.app_name = app_name
        self.facility = facility
        self.hostname = hostname or socket.gethostname()
        self.process_id = process_id or os.getpid()
        
        # 日志配置
        self.log_to_syslog = False
        self.log_to_file = False
        self.log_to_siem = False
        self.siem_format = SIEMFormat.JSON
        
        # 输出目标
        self.file_path = None
        self.syslog_address = ('localhost', 514)
        self.siem_endpoint = None
        
        # 日志记录器
        self.logger = None
        self.syslog_handler = None
        self.file_handler = None
        self.siem_handler = None
        
        # 线程锁
        self._lock = threading.Lock()
        
        # 初始化日志记录器
        self._setup_logger()
    
    def _setup_logger(self):
        """设置日志记录器"""
        self.logger = logging.getLogger(self.app_name)
        self.logger.setLevel(logging.DEBUG)
        
        # 清除现有处理器
        self.logger.handlers.clear()
        
        # 设置格式器
        formatter = logging.Formatter(
            '%(asctime)s %(hostname)s %(name)s[%(process)d]: %(levelname)s - %(message)s',
            datefmt='%Y-%m-%dT%H:%M:%S'
        )
        
        # 添加额外字段
        old_factory = logging.getLogRecordFactory()
        
        def record_factory(*args, **kwargs):
            record = old_factory(*args, **kwargs)
            record.hostname = self.hostname
            record.process = self.process_id
            return record
        
        logging.setLogRecordFactory(record_factory)
    
    def configure_syslog(self, address: tuple = ('localhost', 514), 
                        facility: Optional[LogFacility] = None):
        """
        配置syslog输出
        
        Args:
            address: syslog服务器地址
            facility: 日志设施
        """
        self.log_to_syslog = True
        self.syslog_address = address
        
        if facility:
            self.facility = facility
        
        # 创建syslog处理器
        try:
            self.syslog_handler = logging.handlers.SysLogHandler(
                address=address,
                facility=self.facility.value
            )
            
            # 设置RFC 5424格式
            syslog_formatter = RFC5424Formatter(
                app_name=self.app_name,
                hostname=self.hostname,
                process_id=self.process_id
            )
            self.syslog_handler.setFormatter(syslog_formatter)
            
            self.logger.addHandler(self.syslog_handler)
            
        except Exception as e:
            print(f"配置syslog失败: {e}")
    
    def configure_file_logging(self, file_path: str, 
                              max_bytes: int = 10*1024*1024,
                              backup_count: int = 5):
        """
        配置文件日志输出
        
        Args:
            file_path: 日志文件路径
            max_bytes: 最大文件大小
            backup_count: 备份文件数量
        """
        self.log_to_file = True
        self.file_path = file_path
        
        # 确保目录存在
        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        
        # 创建文件处理器
        self.file_handler = logging.handlers.RotatingFileHandler(
            file_path, maxBytes=max_bytes, backupCount=backup_count
        )
        
        # 设置格式器
        file_formatter = logging.Formatter(
            '%(asctime)s [%(levelname)s] %(hostname)s %(name)s[%(process)d]: %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        self.file_handler.setFormatter(file_formatter)
        
        self.logger.addHandler(self.file_handler)
    
    def configure_siem_logging(self, endpoint: str, 
                              format_type: SIEMFormat = SIEMFormat.JSON,
                              api_key: Optional[str] = None):
        """
        配置SIEM系统日志输出
        
        Args:
            endpoint: SIEM系统端点
            format_type: 日志格式类型
            api_key: API密钥
        """
        self.log_to_siem = True
        self.siem_endpoint = endpoint
        self.siem_format = format_type
        
        # 创建SIEM处理器
        self.siem_handler = SIEMHandler(
            endpoint=endpoint,
            format_type=format_type,
            api_key=api_key
        )
        
        self.logger.addHandler(self.siem_handler)
    
    def log_event(self, level: LogLevel, message: str, 
                  event_data: Optional[Dict[str, Any]] = None,
                  event_type: str = "general",
                  source_ip: Optional[str] = None,
                  user: Optional[str] = None):
        """
        记录事件日志
        
        Args:
            level: 日志级别
            message: 日志消息
            event_data: 事件数据
            event_type: 事件类型
            source_ip: 源IP地址
            user: 用户名
        """
        with self._lock:
            # 构建结构化日志数据
            log_data = {
                'timestamp': datetime.utcnow().isoformat() + 'Z',
                'hostname': self.hostname,
                'app_name': self.app_name,
                'process_id': self.process_id,
                'level': level.name,
                'event_type': event_type,
                'message': message
            }
            
            # 添加可选字段
            if source_ip:
                log_data['source_ip'] = source_ip
            if user:
                log_data['user'] = user
            if event_data:
                log_data['event_data'] = event_data
            
            # 转换为Python logging级别
            python_level = self._convert_log_level(level)
            
            # 记录日志
            self.logger.log(python_level, json.dumps(log_data, ensure_ascii=False))
    
    def log_security_event(self, event_type: str, message: str,
                          severity: LogLevel = LogLevel.WARNING,
                          source_ip: Optional[str] = None,
                          user: Optional[str] = None,
                          additional_data: Optional[Dict[str, Any]] = None):
        """
        记录安全事件
        
        Args:
            event_type: 事件类型
            message: 事件消息
            severity: 严重程度
            source_ip: 源IP地址
            user: 用户名
            additional_data: 附加数据
        """
        event_data = {
            'category': 'security',
            'event_type': event_type,
            'severity': severity.name
        }
        
        if additional_data:
            event_data.update(additional_data)
        
        self.log_event(
            level=severity,
            message=message,
            event_data=event_data,
            event_type='security',
            source_ip=source_ip,
            user=user
        )
    
    def log_system_event(self, operation: str, status: str,
                        details: Optional[Dict[str, Any]] = None):
        """
        记录系统事件
        
        Args:
            operation: 操作类型
            status: 操作状态
            details: 操作详情
        """
        event_data = {
            'category': 'system',
            'operation': operation,
            'status': status
        }
        
        if details:
            event_data.update(details)
        
        level = LogLevel.INFO if status == 'success' else LogLevel.ERROR
        
        self.log_event(
            level=level,
            message=f"系统操作: {operation} - {status}",
            event_data=event_data,
            event_type='system'
        )
    
    def log_audit_event(self, action: str, resource: str,
                       user: str, result: str,
                       source_ip: Optional[str] = None,
                       additional_info: Optional[Dict[str, Any]] = None):
        """
        记录审计事件
        
        Args:
            action: 执行的动作
            resource: 访问的资源
            user: 执行用户
            result: 执行结果
            source_ip: 源IP地址
            additional_info: 附加信息
        """
        event_data = {
            'category': 'audit',
            'action': action,
            'resource': resource,
            'result': result
        }
        
        if additional_info:
            event_data.update(additional_info)
        
        level = LogLevel.NOTICE if result == 'success' else LogLevel.WARNING
        
        self.log_event(
            level=level,
            message=f"审计事件: {user} {action} {resource} - {result}",
            event_data=event_data,
            event_type='audit',
            source_ip=source_ip,
            user=user
        )
    
    def _convert_log_level(self, level: LogLevel) -> int:
        """转换日志级别到Python logging级别"""
        mapping = {
            LogLevel.EMERGENCY: logging.CRITICAL,
            LogLevel.ALERT: logging.CRITICAL,
            LogLevel.CRITICAL: logging.CRITICAL,
            LogLevel.ERROR: logging.ERROR,
            LogLevel.WARNING: logging.WARNING,
            LogLevel.NOTICE: logging.INFO,
            LogLevel.INFO: logging.INFO,
            LogLevel.DEBUG: logging.DEBUG
        }
        return mapping.get(level, logging.INFO)
    
    def close(self):
        """关闭日志记录器"""
        if self.syslog_handler:
            self.syslog_handler.close()
            self.logger.removeHandler(self.syslog_handler)
        
        if self.file_handler:
            self.file_handler.close()
            self.logger.removeHandler(self.file_handler)
        
        if self.siem_handler:
            self.siem_handler.close()
            self.logger.removeHandler(self.siem_handler)


class RFC5424Formatter(logging.Formatter):
    """RFC 5424 syslog格式器"""
    
    def __init__(self, app_name: str, hostname: str, process_id: int):
        super().__init__()
        self.app_name = app_name
        self.hostname = hostname
        self.process_id = process_id
    
    def format(self, record):
        """格式化日志记录为RFC 5424格式"""
        # 计算优先级
        facility = 16  # LOCAL0
        severity = self._get_severity(record.levelno)
        priority = facility * 8 + severity
        
        # 构建RFC 5424消息
        timestamp = datetime.fromtimestamp(record.created).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
        
        # 结构化数据
        structured_data = f'[privilege_ma@32473 level="{record.levelname}" pid="{self.process_id}"]'
        
        # 消息内容
        message = record.getMessage()
        
        # 完整的RFC 5424格式
        rfc5424_msg = (
            f"<{priority}>1 {timestamp} {self.hostname} "
            f"{self.app_name} {self.process_id} - {structured_data} {message}"
        )
        
        return rfc5424_msg
    
    def _get_severity(self, levelno: int) -> int:
        """获取syslog严重程度"""
        if levelno >= logging.CRITICAL:
            return 2  # Critical
        elif levelno >= logging.ERROR:
            return 3  # Error
        elif levelno >= logging.WARNING:
            return 4  # Warning
        elif levelno >= logging.INFO:
            return 6  # Informational
        else:
            return 7  # Debug


class SIEMHandler(logging.Handler):
    """SIEM系统日志处理器"""
    
    def __init__(self, endpoint: str, format_type: SIEMFormat, api_key: Optional[str] = None):
        super().__init__()
        self.endpoint = endpoint
        self.format_type = format_type
        self.api_key = api_key
    
    def emit(self, record):
        """发送日志到SIEM系统"""
        try:
            # 格式化日志
            if self.format_type == SIEMFormat.CEF:
                formatted_log = self._format_cef(record)
            elif self.format_type == SIEMFormat.LEEF:
                formatted_log = self._format_leef(record)
            elif self.format_type == SIEMFormat.JSON:
                formatted_log = self._format_json(record)
            else:
                formatted_log = self.format(record)
            
            # 发送到SIEM系统（这里只是示例，实际需要根据SIEM系统API实现）
            self._send_to_siem(formatted_log)
            
        except Exception:
            self.handleError(record)
    
    def _format_cef(self, record) -> str:
        """格式化为CEF格式"""
        # CEF格式示例
        return (
            f"CEF:0|PrivilegeMA|SecurityTool|1.1|{record.levelname}|"
            f"{record.getMessage()}|{self._get_cef_severity(record.levelno)}|"
            f"src={getattr(record, 'source_ip', 'unknown')} "
            f"suser={getattr(record, 'user', 'unknown')}"
        )
    
    def _format_leef(self, record) -> str:
        """格式化为LEEF格式"""
        # LEEF格式示例
        return (
            f"LEEF:2.0|PrivilegeMA|SecurityTool|1.1|{record.levelname}|"
            f"devTime={int(record.created * 1000)}|"
            f"src={getattr(record, 'source_ip', 'unknown')}|"
            f"usrName={getattr(record, 'user', 'unknown')}|"
            f"msg={record.getMessage()}"
        )
    
    def _format_json(self, record) -> str:
        """格式化为JSON格式"""
        log_data = {
            'timestamp': datetime.fromtimestamp(record.created).isoformat(),
            'level': record.levelname,
            'message': record.getMessage(),
            'source': 'privilege_ma',
            'hostname': getattr(record, 'hostname', 'unknown'),
            'process_id': getattr(record, 'process', 0)
        }
        
        # 添加可选字段
        if hasattr(record, 'source_ip'):
            log_data['source_ip'] = record.source_ip
        if hasattr(record, 'user'):
            log_data['user'] = record.user
        
        return json.dumps(log_data)
    
    def _get_cef_severity(self, levelno: int) -> int:
        """获取CEF严重程度"""
        if levelno >= logging.CRITICAL:
            return 10
        elif levelno >= logging.ERROR:
            return 7
        elif levelno >= logging.WARNING:
            return 5
        elif levelno >= logging.INFO:
            return 3
        else:
            return 1
    
    def _send_to_siem(self, log_data: str):
        """发送日志到SIEM系统"""
        # 这里应该实现实际的SIEM系统API调用
        # 例如：HTTP POST到SIEM系统端点
        pass


# 全局日志记录器实例
_global_logger: Optional[StandardLogger] = None


def get_logger() -> StandardLogger:
    """获取全局日志记录器"""
    global _global_logger
    if _global_logger is None:
        _global_logger = StandardLogger()
    return _global_logger


def configure_logging(log_to_syslog: bool = False,
                     log_to_file: bool = False,
                     file_path: Optional[str] = None,
                     syslog_address: tuple = ('localhost', 514),
                     siem_endpoint: Optional[str] = None,
                     siem_format: SIEMFormat = SIEMFormat.JSON):
    """
    配置全局日志记录
    
    Args:
        log_to_syslog: 是否输出到syslog
        log_to_file: 是否输出到文件
        file_path: 日志文件路径
        syslog_address: syslog服务器地址
        siem_endpoint: SIEM系统端点
        siem_format: SIEM日志格式
    """
    logger = get_logger()
    
    if log_to_syslog:
        logger.configure_syslog(address=syslog_address)
    
    if log_to_file and file_path:
        logger.configure_file_logging(file_path)
    
    if siem_endpoint:
        logger.configure_siem_logging(siem_endpoint, siem_format)


def main():
    """主函数 - 测试日志功能"""
    print("标准化日志输出模块测试")
    print("="*50)
    
    # 创建日志记录器
    logger = StandardLogger()
    
    # 配置文件日志
    logger.configure_file_logging('/tmp/privilege_ma.log')
    
    # 测试不同类型的日志
    logger.log_system_event(
        operation="module_initialization",
        status="success",
        details={"module": "standard_logger", "version": "1.0"}
    )
    
    logger.log_security_event(
        event_type="privilege_escalation_attempt",
        message="检测到权限提升尝试",
        severity=LogLevel.WARNING,
        source_ip="192.168.1.100",
        user="testuser",
        additional_data={"method": "sudo", "command": "/bin/bash"}
    )
    
    logger.log_audit_event(
        action="file_access",
        resource="/etc/passwd",
        user="root",
        result="success",
        source_ip="127.0.0.1",
        additional_info={"access_type": "read", "tool": "privilege_ma"}
    )
    
    # 测试一般事件日志
    logger.log_event(
        level=LogLevel.INFO,
        message="权限维持系统启动完成",
        event_data={"startup_time": time.time()},
        event_type="system_startup"
    )
    
    print("[+] 日志测试完成，请检查 /tmp/privilege_ma.log")
    
    # 关闭日志记录器
    logger.close()


if __name__ == "__main__":
    main()